// constantes utilisé
var LISTE_ELEMENTS = {
	ajouter_texte:'TEXTE',
	ajouter_nombre:'ENTIER',
	ajouter_liste:'LISTE',
	ajouter_article:'ARTICLE',
	ajouter_ouinon:'OUINON',
}
var nb_voxbloc = 0;
var nb_bloc = 0;
var nb_question = 0;

var nb_input = 0;

/* fonctions de gestions des numéros pour tout les voxblocs, blocs et questions */
function nouveauNumeroVoxBloc() {return ++nb_voxbloc;} // retourne un nouveau numero pour les voxblocs
function dernierNumeroVoxBloc() {return nb_voxbloc;} // retourne le numéro du dernier voxbloc créé
function nouveauNumeroBloc() {return ++nb_bloc;} // retourne un numero pour les blocs
function dernierNumeroBloc() {return nb_bloc;} // retourne le numéro du dernier bloc créé
function nouveauNumeroQuestion() {return ++nb_question;} // retourne un numero pour les questions
function dernierNumeroQuestion() {return nb_question;} // retourne le numero de la dernière question créée

// permet d'ajouter un bloc dans l'editeur WYSIWYG
// paramtres :
// - el : l'objet JQuery après lequel insérer le bloc
// - titre : le titre du bloc ('Nom du bloc' par défaut)
function ajouterBloc(el, titre, id_voxbloc) {
	// on obtient un nouveau numero pour ce voxbloc
	var num = nouveauNumeroVoxBloc();
	// gestion des paramètres optionnels
	if(!titre) titre = 'Nom du bloc';
	
	// création du nouveau bloc
	var blocTotal = $('<div/>', {class:'bloc'});
	var nouvelListeEnsembles = $('<div/>', {class:'togglebox_test'});
	var nouveauBloc = $('<div/>', {class:'titre_clic_test', click:function(){
		nouvelListeEnsembles.slideToggle("fast");
	}});
	// création des actions lié au bloc
	var actions = ajouterBlocActions(blocTotal);
	
	// ajout du nouveau bloc
	blocTotal.append(nouveauBloc);
	blocTotal.append(nouvelListeEnsembles);
	el.after(blocTotal);
	// ajout d'un titre pour ce bloc
	nouveauBloc.append(actions);
	nouveauBloc.append($('<input/>', {type:'text', value:titre, class:'input_titre_bloc', name:'voxblocs['+num+'][nom]', click:function(e){e.stopPropagation();}}));
	// ajout de l'id s'il est définit
	if(id_voxbloc) nouveauBloc.append($('<input/>', {type:'hidden', name:'voxblocs['+num+'][id]', value:id_voxbloc}));
	
	// ajout d'un emplacement de bloc après ce bloc
	blocTotal.after(nouvelEmplacementBloc());
	
	// ajout d'un emplacement d'ensemble dans le bloc
	nouvelListeEnsembles.append(nouvelEmplacementEnsemble(num));
}

// permet d'ajouter un ensemble dans l'editeur WYSIWYG
// paramètres :
// - el : l'object JQUERY après lequel ajouter l'élément
// - titre : le titre de l'ensemble ('Nom du bloc' par défaut)
// - num_voxbloc : le numero du voxbloc auquel cet ensemble appartient
function ajouterEnsemble(el, titre, id_bloc, num_voxbloc) {
	// on obtient un nouveau numero pour ce bloc
	var num = nouveauNumeroBloc();
	// gestion des paramètres optionnels
	if(!titre) titre = 'Nom du bloc';
	if(!num_voxbloc) num_voxbloc = dernierNumeroVoxBloc(); // on attribut le numéro du dernier voxbloc créé
	// création des éléments de l'ensemble : un titre et un bloc pour les questions
	var titre_ensemble = $('<input/>', {type:'text', class:'titre_categorie input_nom_ensemble', value:titre, name:'voxblocs['+num_voxbloc+'][blocs]['+num+'][nom]'})
	var bloc_question = $('<div/>');
	
	// création d'un bloc pour contenir tout ça
	var ensemble = $('<div/>', {class:'ensemble'});
	ensemble.append(ajouterBlocActions(ensemble));
	ensemble.append(titre_ensemble);
	ensemble.append(bloc_question);
	
	// ajout de cet ensemble après l'emplacement
	el.after(ensemble);
	// ajout d'un emplacement après cet ensemble
	ensemble.after(nouvelEmplacementEnsemble(num_voxbloc));
	// si l'id est définit, un ajoute un input de type hidden pour indiquer que c'est un élément existant déjà
	if(id_bloc) ensemble.append($('<input/>', {type:'hidden', value:id_bloc, name:'voxblocs['+num_voxbloc+'][blocs]['+num+'][id]'}));
	
	// ajout d'un emplacement de question dans l'ensemble
	bloc_question.append(nouvelEmplacementElement(num_voxbloc, num));
}

// permet d'ajouter un element dans l'editeur WYSIWYG
// paramètres :
// - type : définit le type de l'élément à ajouter. Valeurs supporter : 'TEXTE', 'ENTIER', 'LISTE', 'ARTICLE', 'OUINON'
// - el : l'object JQUERY après lequel ajouter l'élément
// - info : des informations suplémentaires sur l'élément à ajouter. Le format de cette structure est le suivant :
// 	- id_question : l'id de la question (elle existe donc dans la bdd)
// 	- libelle_question : le nom de la question
// 	- question_active_par_defaut : boolean indiquant si la question est active a l'état de départ
// 	- id_categorie : l'id de la categorie correspondante (type ARTICLE uniquement)
// - reponses : les éventuelles réponses pour la question (dans le cas d'une liste par exemple). Le format de cette structure est le suivant :
// 	- id_reponse : l'id de la réponse (elle existe donc dans la bdd)
// 	- libelle_reponse_combo : le libelle de la réponse (type LISTE uniquement)
// - num_voxbloc : le numéro du voxbloc auquel cette question est indirectement rattachée
// - num_bloc : le numéro du bloc auquel cette question est rattachée
// cas particulier : num_voxbloc et num_bloc peuvent valoir 'independant'. Si c'est le cas, alors l'élément aura un 'name' différent (indépendant de tout bloc et ensemble)
function ajouterElement(type, el, info, reponses, num_voxbloc, num_bloc) {
	// obtention d'un numéro pour cette question
	var num = nouveauNumeroQuestion();
	if(!num_voxbloc) num_voxbloc = dernierNumeroVoxBloc(); // on récupère le numéro du dernier voxbloc
	if(!num_bloc) num_bloc = dernierNumeroBloc(); // on récupère le numéro du dernier bloc
	// définition de la valeur de l'attrbut 'name' pour les input
	var valeur_name;
	if(num_voxbloc == 'independant' && num_bloc == 'independant') valeur_name = 'questions['+num+']';
	else valeur_name = 'voxblocs['+num_voxbloc+'][blocs]['+num_bloc+'][questions]['+num+']';
	// gestion des paramètres optionnelles
	var nom_question = 'Nom de la question';
	var active = true;
	if(info) {
		nom_question = info.libelle_question;
		active = info.question_active_par_defaut;
	}
	// création du bloc pour la question
	var nouvelElement = $('<div/>', {class:'question'});
	// création des options
	var optionAction = ajouterBlocActions(nouvelElement);
	// ajout de l'élément affichage par défaut
	var input_active_par_defaut = $('<input/>', {type:'hidden', value:(active?true:false), name:valeur_name+'[active]'});
	var active_par_defaut = $('<img/>', {src:'../../img/eye.png', class:'cliquable'});
	active_par_defaut.active = true;
	active_par_defaut.click(function() {
		// si l'élément est activé, on le desactive
		if(active_par_defaut.active) {
			active_par_defaut.attr('src', '../../img/eye_no.png');
			nouvelElement.addClass('semi_transparent');
			input_active_par_defaut.val(false);
		}
		// sinon, on l'active
		else {
			active_par_defaut.attr('src', '../../img/eye.png');
			nouvelElement.removeClass('semi_transparent');
			input_active_par_defaut.val(true);
		}
		active_par_defaut.active = !active_par_defaut.active;
	});
	if(!active) active_par_defaut.click();
	optionAction.prepend(input_active_par_defaut);
	optionAction.prepend(active_par_defaut);
	// ajout de l'input pour le nom de l'élément
	var input_nom_element = $('<input/>', {type:'text', class:'label_test input_nom_question', value:nom_question, name:valeur_name+'[nom]'});
	nouvelElement.append(optionAction);
	nouvelElement.append(input_nom_element);
	// si l'id est définit, on ajoute un element de type hidden pour l'ajouter
	if(info) nouvelElement.append($('<input/>', {type:'hidden', value:info.id_question, name:valeur_name+'[id]'}));
	nouvelElement.append($('<input/>', {type:'hidden', value:type, name:valeur_name+'[type]'}));
	
	// traitement selon le type de l'élément voulut
	switch(type) {
		case 'TEXTE':
			nouvelElement.append($('<input/>', {type:'text'}));
			break;
		case 'ENTIER':
			nouvelElement.append($('<input/>', {type:'number'}));
			break;
		case 'OUINON':
			nouvelElement.append($('<input type="radio" name="ouinon'+nb_input+'" />'));
			nouvelElement.append(' Oui ');
			nouvelElement.append($('<input type="radio" name="ouinon'+nb_input+'" />'));
			nouvelElement.append(' Non ');
			nb_input++;
			break;
		case 'ARTICLE':
			var liste_categorie = $('<select/>', {name:valeur_name+'[val]'});
			var liste_article = $('<select/>');
			var k_prem; // clé pour la categorie de départ
			// on récupère la categorie si le paramètre info est définit
			if(info) k_prem = info.id_categorie;
			// on remplit la liste des categorie, et au passage on recupère la première si elle est vide
			for (var k in articles) {
				if(!k_prem) k_prem = k;
				liste_categorie.append($('<option/>', {value:articles[k].id_categorie, text:articles[k].description_categorie, selected:(k == k_prem ? 'selected' : false)}));
			}
			// on met la liste d'article à jour quand la liste de categorie change
			liste_categorie.change(function () {
				var indice = liste_categorie.find('option:selected').val();
				liste_article.empty();
				for (var k in articles[indice].articles) {
					liste_article.append($('<option/>', {value:articles[indice].articles[k].id_article, text:articles[indice].articles[k].description_article}));
				}
			});
			// on ajoute les deux listes
			optionAction.prepend(liste_categorie);
			nouvelElement.append(liste_article);
			liste_categorie.change();
			break;
		case 'LISTE':
			var optVide = $('<option/>', {value:'', text:''});
			var optNew = $('<option/>', {value:'new', text:'<ajouter un élément>', css:{backgroundColor:'#88FF88'}});
			var spanSuppr = $('<span/>', {name:'suppression'});
			var divHidden = $('<div/>', {css:{display:'none'}});
			var countHidden = 0; // utilisation d'un compteur pour associer deux à deux les éléments de la liste avec leurs hidden
			var liste = $('<select/>', {change:function (ev, val) {
				var opt = liste.find('option:selected');
				// on nettoie spanSuppr au cas où il y est un bouton supprimer
				spanSuppr.empty();
				// si l'utilisateur clique sur l'option "créer un nouvel élément", alors on lui demande le nom de l'élément
				if(opt.get(0) == optNew.get(0)) {
					var nouvelOption = prompt("Nouvel élément dans la liste", "Saisissez le nom de l'élément à ajouter");
					if(nouvelOption && nouvelOption != '') {
						ajouterOptionDansListe(nouvelOption);
					}
					optVide.attr('selected', 'selected');
				}
				// sinon, si l'utilisateur à cliqué sur un de ses éléments, on lui affiche le bouton supprimer
				else if(opt != optVide.get(0)) {
					spanSuppr.append($('<img/>', {src:'../../img/delete.png', alt:'delete', title:'Supprimer cet élément', click:function(){
						var opt = liste.find('option:selected');
						divHidden.find("div[name='"+opt.attr('name')+"']:first").remove();
						opt.remove();
						liste.find('option:first').attr("selected", "selected");
						spanSuppr.empty();
					}}));
				}
			}});
			// fonction pour ajouter une option dans la liste
			function ajouterOptionDansListe(text, id) {
				countHidden++;
				var nouvelle_option = $('<option/>', {value:text, text:text, name:'input'+countHidden});
				var div_hiddens = $('<div/>', {name:'input'+countHidden});
				var hidden_option = $('<input/>', {type:'hidden', value:text, name:valeur_name+'[reponses]['+countHidden+'][nom]'});
				if(id) div_hiddens.append($('<input/>', {type:'hidden', value:id, name:valeur_name+'[reponses]['+countHidden+'][id]'}));
				div_hiddens.append(hidden_option);
				divHidden.append(div_hiddens);
				optNew.before(nouvelle_option);
			}
			// on ajoute les éléments à l'affichage
			liste.append(optVide);
			liste.append(optNew);
			nouvelElement.append(liste);
			nouvelElement.append(divHidden);
			nouvelElement.append(spanSuppr);
			// si l'argument reponses est définit, alors on le parcour pour ajouter l'ensemble des réponses de la liste
			if(reponses) {
				for (var k in reponses) {
					ajouterOptionDansListe(reponses[k].libelle_reponse_combo, reponses[k].id_reponse);
				}
			}
			break;
	}
	
	// on ajoute tout ça après l'emplacement 'el'
	el.after(nouvelElement);
	// on rajoute un nouvel emplacement
	nouvelElement.after(nouvelEmplacementElement(num_voxbloc, num_bloc));
}

// permet de créer un bloc contenant les actions de base communes aux éléments : monter, descendre, supprimer
// paramètres :
// - element : l'élément sur lequel travaillé lors des actions
function ajouterBlocActions(element) {
	var nomClasse = element.attr('class');
	var optionAction = $('<div/>', {class:'action_'+nomClasse});
	var act_monter = $('<img/>', {src:'../../img/arrow_up.png', click:function(e) {
		// on récupère la question précédente
		var voisin = element.prevAll('.'+nomClasse+':first');
		// si il y en a une, on les inverses
		if(voisin.length != 0) {
			var separateur = element.prev();
			separateur.before(element);
			separateur.after(voisin);
		}
		e.stopPropagation();
	}}); // option pour monter l'élément
	var act_descendre = $('<img/>', {src:'../../img/arrow_down.png', click:function(e) {
		// on récupère la question précédente
		var voisin = element.nextAll('.'+nomClasse+':first');
		// si il y en a une, on les inverses
		if(voisin.length != 0) {
			var separateur = element.next();
			separateur.after(element);
			separateur.before(voisin);
		}
		e.stopPropagation();
	}}); // option pour descendre l'élément
	var act_supprimer = $('<img/>', {src:'../../img/delete.png', click:function(e) {
		element.next().remove();
		element.hide('fold', {size:1}, 1000, function() {element.remove();});
		e.stopPropagation();
	}}); // option pour supprimer l'élément
	optionAction.append(act_monter);
	optionAction.append(act_descendre);
	optionAction.append(act_supprimer);
	return optionAction;
}


// permet de créer un nouvel emplacement droppable pour l'ajout de bloc
// retourne l'objet jquery ainsi créé
function nouvelEmplacementBloc() {
	var el = $('<div/>', {
		class:'emplacement_bloc',
	});
	el.droppable({
		tolerance: 'touch',
		accept:'.nouveau_bloc',
		drop:function(event, object) {
			ajouterBloc(el);
		},
		activeClass:'droppable_active',
		hoverClass:'droppable_hover',
	});
	return el;
}

// permet de créer un nouvel emplacement droppable pour l'ajout d'ensemble
// paramètres :
// - num_voxbloc : le numero du voxbloc auquel cet emplacement doit correspondre
// retourne l'objet jquery ainsi créé
function nouvelEmplacementEnsemble(num_voxbloc) {
	var el = $('<div/>', {
		class:'emplacement_ensemble',
	});
	el.droppable({
		tolerance: 'touch',
		accept:'.nouvel_ensemble',
		drop:function(event, object) {
			ajouterEnsemble(el, undefined, undefined, num_voxbloc);
		},
		activeClass:'droppable_active',
		hoverClass:'droppable_hover',
	});
	return el;
}

// permet de créer un nouvel emplacement droppable pour l'ajout d'élément
// paramètres :
// - num_voxbloc : le numéro du voxbloc auquel les questions créées à cet emplacement sont indirectement rattachées
// - num_bloc : le numéro du blo auquel cette question créées à cet emplacement sont rattachées
// special : num_voxbloc et num_bloc peuvent valoir 'independant'. Si c'est le cas, alors les éléments créer via cet emplacement n'auront pas de bloc ni d'ensemble
// retourne l'objet jquery ainsi créé
function nouvelEmplacementElement(num_voxbloc, num_bloc) {
	var el = $('<div/>', {
		class:'emplacement_question',
	});
	el.droppable({
		tolerance: 'touch',
		accept:'.nouvel_element',
		drop:function(event, object) {
			ajouterElement(LISTE_ELEMENTS[object.draggable.get(0).id], el, undefined, undefined, num_voxbloc, num_bloc);
		},
		activeClass:'droppable_active',
		hoverClass:'droppable_hover',
	});
	return el;
}

// permet d'ajouter un ensemble de questions. Utilisé lors du chargement de la page une fois que l'on à récupéré les questions de la BDD.
// paramètres :
// - questions : une structure de données complexes contenant l'ensemble des blocs, des sous-blocs et des questions. La description est faite ci-dessous :
// Description de la structure (au format JSON) attendu de 'questions' :
// [			// zéro ou plusieurs fois les éléments ci-dessous
// 	info_VoxBloc:
// 	{
// 		id_vox_bloc: ((l'id du vox bloc:integer))
// 		rang_vox_bloc: ((le rang du vox bloc:integer))
// 		libelle_vox_bloc: ((le libelle du vox bloc:string))
// 	}
// 	BlocsQuestion:
// 	[			// zéro ou plusieurs fois les éléments ci-dessous
// 		{
// 			info_BlocQuestion:
// 			{
// 				id_bloc: ((l'id du bloc:integer))
// 				rang_bloc: ((le rang du bloc:integer))
// 				description_bloc: ((la description du bloc:string))
// 				id_vox_bloc: ((l'id du vox bloc correspondant:integer))
// 			}
// 			Questions:
// 			[				// zéro ou plusieurs fois les éléments ci-dessous
// 				{
// 					info:
// 					{
// 						id_question: ((l'id de la question:integer))
// 						type_reponse: ((le type de la réponse:string))
// 						question_sur_societe: ((un boolean indiquant si c'est une question sur la societe:boolean))
// 						rang_question: ((le rang de la question:integer))
// 						libelle_question: ((le libelle de la question:string))
// 						question_active_par_defaut: ((un boolean indiquant si la question est active au départ:boolean))
// 						id_bloc: ((l'id du bloc parent:integer))
// 						id_categorie: ((l'id de la categorie dans le cas où c'est une question de type ARTICLE:integer))
// 					}
// 					Reponses:	
// 					[			// zéro ou plusieurs fois les éléments ci-dessous
// 						{
// 							id_reponse: ((l'id de la réponse:integer))
// 							rang_reponse: ((le rang de la réponse:integer))
// 							libelle_reponse_combo: ((le libelle de la reponse si c'est un type LISTE:string))
// 							valeur_min: ((la valeur min si c'est une question de type ENTIER:integer))
// 							valeur_max: ((la valeur max si c'est une question de type ENTIER:integer))
// 							reponse_texte: ((la valeur du texte si c'est une question de type TEXTE:string))
// 							reponse_oui_non: ((la valeur du champ si c'est une question de type OUINON:boolean))
// 							id_question: ((l'id de la question contenant la réponse:integer))
// 							id_article: ((l'id de l'article si c'est une question de type ARTICLE:integer))
// 							id_statut_reponse: ((l'id du statut par défaut de la réponse:integer))
// 						}
// 					]
// 				}
// 			]
// 		}
// 	]
// ]
function ajouterQuestionsExistantes(vbs) {
	// on parcourt les voxbloc
	for (var k_voxbloc in vbs) {
		ajouterBloc($('.emplacement_bloc:last'), vbs[k_voxbloc].info_VoxBloc.libelle_vox_bloc, vbs[k_voxbloc].info_VoxBloc.id_vox_bloc);
		
		// on parcourt les ensembles de ce bloc
		for (var k_ensemble in vbs[k_voxbloc].BlocsQuestions) {
			ajouterEnsemble($('.emplacement_ensemble:last'), vbs[k_voxbloc].BlocsQuestions[k_ensemble].info_BlocQuestion.description_bloc, vbs[k_voxbloc].BlocsQuestions[k_ensemble].info_BlocQuestion.id_bloc);
			
			// on parcourt les questions de cet ensemble
			for (var k_question in vbs[k_voxbloc].BlocsQuestions[k_ensemble].Questions) {
				ajouterElement(vbs[k_voxbloc].BlocsQuestions[k_ensemble].Questions[k_question].info.type_reponse, $('.emplacement_question:last'), vbs[k_voxbloc].BlocsQuestions[k_ensemble].Questions[k_question].info, vbs[k_voxbloc].BlocsQuestions[k_ensemble].Questions[k_question].Reponses);
			}
		}
	}
}

// permet d'ajouter les questions sur la société. Doit être appelé avant 'ajouterQuestionsExistantes'.
// paramètre :
// - question_societes : une structure de données relativement complexe contenant des informations sur les questions et leurs réponses. Le format est décrit ci-dessous :
// [				// zéro ou plusieurs fois les éléments ci-dessous
// 	{
// 		info:
// 		{
// 			id_question: ((l'id de la question:integer))
// 			type_reponse: ((le type de la réponse:string))
// 			question_sur_societe: ((un boolean indiquant si c'est une question sur la societe:boolean))
// 			rang_question: ((le rang de la question:integer))
// 			libelle_question: ((le libelle de la question:string))
// 			question_active_par_defaut: ((un boolean indiquant si la question est active au départ:boolean))
// 			id_bloc: ((l'id du bloc parent:integer))
// 			id_categorie: ((l'id de la categorie dans le cas où c'est une question de type ARTICLE:integer))
// 		}
// 		Reponses:	
// 		[			// zéro ou plusieurs fois les éléments ci-dessous
// 			{
// 				id_reponse: ((l'id de la réponse:integer))
// 				rang_reponse: ((le rang de la réponse:integer))
// 				libelle_reponse_combo: ((le libelle de la reponse si c'est un type LISTE:string))
// 				valeur_min: ((la valeur min si c'est une question de type ENTIER:integer))
// 				valeur_max: ((la valeur max si c'est une question de type ENTIER:integer))
// 				reponse_texte: ((la valeur du texte si c'est une question de type TEXTE:string))
// 				reponse_oui_non: ((la valeur du champ si c'est une question de type OUINON:boolean))
// 				id_question: ((l'id de la question contenant la réponse:integer))
// 				id_article: ((l'id de l'article si c'est une question de type ARTICLE:integer))
// 				id_statut_reponse: ((l'id du statut par défaut de la réponse:integer))
// 			}
// 		]
// 	}
// ]
function ajouterQuestionsSocietes(question_societes) {
	// on parcourt les questions et on les ajoutes
	for (var k_question in question_societes) {
		ajouterElement(question_societes[k_question].type_reponse,
						$('.emplacement_question:last'),
						question_societes[k_question],
						question_societes[k_question].reponses,
						"independant",
						"independant");
	}
}

// vérifie si toutes les listes ont au moins un éléments à prendre en compte
function verifierFormulaire() {
	var typeListe = $('input[value="LISTE"]');
	var result = true;
	var select = $('input[value="LISTE"]').next('select').filter(function () {return $(this).children().length < 3});
	
	if(select.length > 0) {
		result = false;
		select.css("backgroundColor", '#FFAAAA');
	}
	return result;
}
